#pragma once 
#include<vector>
#include<queue>
#include<pthread.h>
#include<semaphore.h>



template<typename T>
class RingQueue
{
    private:
        //1. 环形队列
        std::vector<T> _ring_queue;
        int _capacity;//容量上限
        //2. 生产消费下标
        int _productor_index;
        int _consumer_index;
        //3. 定义信号量
        sem_t _room_sem;//生产者关心
        sem_t _data_sem;//消费者关心
        //4. 定义锁，维护多生产多消费之间的互斥关系
        pthread_mutex_t _productor_mutex;
        pthread_mutex_t _consumer_mutex;
    private:
        void P(sem_t& sem)
        {
            sem_wait(&sem);
        }
        void V(sem_t& sem)
        {
            sem_post(&sem);
        }
        void Lock(pthread_mutex_t& mutex)
        {
            pthread_mutex_lock(&mutex);
        }
        void Unlock(pthread_mutex_t& mutex)
        {
            pthread_mutex_unlock(&mutex);
        }
    public: 
        RingQueue(int cap)
        :_ring_queue(cap)
        ,_capacity(cap)
        ,_productor_index(0)
        ,_consumer_index(0)
        {
            sem_init(&_room_sem,0,_capacity);
            sem_init(&_data_sem,0,0);
            pthread_mutex_init(&_productor_mutex,nullptr);
            pthread_mutex_init(&_consumer_mutex,nullptr);
        }
        void Enqueue(const T& in)
        {
            //生产行为
            P(_room_sem);
            Lock(_productor_mutex);
            //一定有空间
            _ring_queue[_productor_index++] = in;
            _productor_index %= _capacity;
            Unlock(_productor_mutex);
            V(_data_sem);
        }
        void Pop(T* out)
        {
            //消费行为
            P(_data_sem);
            Lock(_consumer_mutex);
            *out = _ring_queue[_consumer_index++];
            _consumer_index %= _capacity;
            Unlock(_consumer_mutex);
            V(_room_sem);
        }
        ~RingQueue()
        {
            sem_destroy(&_room_sem);//销毁信号量
            sem_destroy(&_data_sem);
            pthread_mutex_destroy(&_productor_mutex);//销毁互斥量
            pthread_mutex_destroy(&_consumer_mutex);
        }
};  
